<template>
  <div class="app-container">

    <el-row :gutter="20">
      <el-form ref="form" :rules="rules" :model="form" label-width="80px" inline>
        <el-form-item label="迷宫高度" prop="length">
          <el-input-number v-model="form.length" controls-position="right" :min="3" :max="999999"></el-input-number>
        </el-form-item>
        <el-form-item label="迷宫宽度" prop="width">
          <el-input-number v-model="form.width" controls-position="right" :min="3" :max="999999"></el-input-number>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="drawLabyrinth(false)">生成迷宫</el-button>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="dialogVisible = true">上传迷宫</el-button>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="downloadLabyrinth" :disabled="!canvas">下载迷宫(csv)</el-button>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="drawLabyrinth(true)" :disabled="!canvas">刷新迷宫</el-button>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="drawPath" :disabled="!canvas">绘制路线(BFS)</el-button>
        </el-form-item>
      </el-form>
    </el-row>

    <el-row :gutter="20">
      <el-form ref="form" :rules="rules" :model="form" label-width="80px" inline>
        <el-form-item label="迷宫起点x" prop="startX">
          <el-input-number v-model="form.start.x" controls-position="right" :min="1"
                           :max="form.length"></el-input-number>
        </el-form-item>
        <el-form-item label="迷宫起点y" prop="startY">
          <el-input-number v-model="form.start.y" controls-position="right" :min="1"
                           :max="form.width"></el-input-number>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="drawStart" :disabled="!canvas">设置起点</el-button>
        </el-form-item>
        <el-form-item label="迷宫终点x" prop="endX">
          <el-input-number v-model="form.end.x" controls-position="right" :min="1" :max="form.length"></el-input-number>
        </el-form-item>
        <el-form-item label="迷宫终点y" prop="endY">
          <el-input-number v-model="form.end.y" controls-position="right" :min="1" :max="form.width"></el-input-number>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="drawEnd" :disabled="!canvas">设置终点</el-button>
        </el-form-item>
      </el-form>
    </el-row>

    <el-row :gutter="20">
      <el-col :span="16">
        <canvas ref="labyrinthArea" class="labyrinth-area"></canvas>
      </el-col>

      <el-col :span="8">
        <div class="appearance-area">
          <div class="distance">距离: {{ distance }}</div>
          <div class="path">
            最短路径：
            <span v-for="(item, index) in path">
              ({{ item.x }}, {{ item.y }}) {{ index === path.length - 1 ? '' : '->' }}
            </span>
          </div>
        </div>
      </el-col>
    </el-row>

    <el-dialog title="上传迷宫" width="400px" :visible.sync="dialogVisible">
      <el-upload class="upload" drag action="http://localhost:81/api/generate/labyrinth/upload/csv"
                 accept=".csv" :multiple="false" :limit="1" :on-success="handleUploadOnSuccess">
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">
          只能上传csv文件，且不超过1MB
          <div>墙：<span style="color: #7f8c8d;">GREY</span>，路：<span style="color: #ccc;">WHITE</span></div>
        </div>
      </el-upload>
    </el-dialog>
  </div>
</template>
<script>
import axios from "axios";

export default {
  name: 'MapEdit',
  data() {
    return {
      form: {
        length: 11,
        width: 11,
        start: {x: 1, y: 1},
        end: {x: 1, y: 1}
      },
      canvas: null,
      ctx: null,
      rules: {},
      points: null,
      prevStart: {},
      prevEnd: {},
      isDrawStart: false,
      isDrawEnd: false,
      path: null,
      distance: null,
      dialogVisible: false
    }
  },
  methods: {
    /**
     * 获取迷宫数据
     */
    async getLabyrinth() {
      const response = await axios.get('http://localhost:81/api/generate/labyrinth', {
        params: {
          length: this.form.length,
          width: this.form.width,
        }
      })
      this.points = response.data.data;
    },
    /**
     * 绘制迷宫
     * @param isRefresh 是否刷新迷宫
     */
    async drawLabyrinth(isRefresh) {
      if (!isRefresh) {
        this.canvas = this.$refs.labyrinthArea;
        if (!this.canvas.getContext) {
          return
        }
        this.canvas.height = (this.form.length + 1) * 50
        this.canvas.width = (this.form.width + 1) * 50
        this.ctx = this.canvas.getContext('2d');
        await this.getLabyrinth()
      } else {
        this.canvas.height = (this.form.length + 1) * 50
        this.canvas.width = (this.form.width + 1) * 50
        this.prevStart = {}
        this.prevEnd = {}
        this.isDrawStart = false
        this.isDrawEnd = false
        this.path = null
        this.distance = null
        this.form = {
          length: this.form.length,
          width: this.form.width,
          start: this.form.start,
          end: this.form.end,
        }
      }

      for (let y = 0; y < this.form.length; y++) {
        this.ctx.font = '15px sans-serif'
        this.ctx.fillText(`${y}`, 20, (y + 1) * 50 + 30)
        for (let x = 0; x < this.form.width; x++) {
          if (y === 0) {
            this.ctx.fillText(`${x}`, (x + 1) * 50 + 20, 30)
          }
          let xp = (x + 1) * 50
          let yp = (y + 1) * 50
          if (this.points[y][x].type === 'GREY') {
            this.ctx.fillStyle = '#7f8c8d'
            this.ctx.strokeStyle = 'black'

          } else if (this.points[y][x].type === 'WHITE') {
            this.ctx.fillStyle = '#fff'
            this.ctx.strokeStyle = 'black'
          }
          this.ctx.fillRect(xp, yp, 50, 50)
          this.ctx.strokeRect(xp, yp, 50, 50);
        }
      }
    },
    /**
     * 绘制路径
     */
    drawPath() {
      if (this.isDrawStart && this.isDrawEnd) {
        let data = {
          start: {x: this.form.start.y, y: this.form.start.x},
          end: {x: this.form.end.y, y: this.form.end.x}
        }
        axios.post('http://localhost:81/api/calc/shortest/path', data)
            .then((response) => {
              this.path = response.data.data.points
              this.distance = response.data.data.distance

              for (let i = 0; i < this.distance + 1; i++) {
                let xp = (this.path[i].y + 1) * 50
                let yp = (this.path[i].x + 1) * 50
                if (i === 0) {
                  this.ctx.fillStyle = '#d63031'
                } else if (i === this.distance) {
                  this.ctx.fillStyle = '#2ecc71'
                } else {
                  this.ctx.fillStyle = '#00a8ff'
                }

                this.ctx.strokeStyle = 'black'
                this.ctx.fillRect(xp, yp, 50, 50)
                this.ctx.strokeRect(xp, yp, 50, 50);
              }
            })
      } else {
        this.$message.warning('请先设置好起点和终点！')
      }
    },
    /**
     * 绘制起点
     */
    drawStart() {
      if (this.prevStart !== {}) {
        // 判断是否被终点覆盖
        if (this.form.end.x !== this.prevStart.x || this.form.end.y !== this.prevStart.y) {
          // 清除上一个起点
          let xp = (this.prevStart.x + 1) * 50
          let yp = (this.prevStart.y + 1) * 50
          this.ctx.fillStyle = '#fff'
          this.ctx.strokeStyle = 'black'
          this.ctx.fillRect(xp, yp, 50, 50)
          this.ctx.strokeRect(xp, yp, 50, 50);
        }
      }

      if (this.points[this.form.start.y][this.form.start.x].type === 'WHITE') {
        // 绘制新起点
        let xp = (this.form.start.x + 1) * 50
        let yp = (this.form.start.y + 1) * 50
        this.ctx.fillStyle = '#d63031'
        this.ctx.strokeStyle = 'black'
        this.ctx.fillRect(xp, yp, 50, 50)
        this.ctx.strokeRect(xp, yp, 50, 50);
        // 判断是否覆盖终点
        if (this.form.start.x === this.form.end.x && this.form.start.y === this.form.end.y) {
          this.isDrawEnd = false;
        }
        this.isDrawStart = true;
        this.prevStart = {x: this.form.start.x, y: this.form.start.y}
      } else {
        this.$message.warning(`(${this.form.start.x},${this.form.start.y})不为路，无法设置为起点！`)
      }
    },
    /**
     * 绘制终点
     */
    drawEnd() {
      if (this.isDrawEnd !== {}) {
        // 判断是否被起点覆盖
        if (this.form.start.x !== this.prevEnd.x || this.form.start.y !== this.prevEnd.y) {
          // 清除上一个终点
          let xp = (this.prevEnd.x + 1) * 50
          let yp = (this.prevEnd.y + 1) * 50
          this.ctx.fillStyle = '#fff'
          this.ctx.strokeStyle = 'black'
          this.ctx.fillRect(xp, yp, 50, 50)
          this.ctx.strokeRect(xp, yp, 50, 50);
        }
      }

      if (this.points[this.form.end.y][this.form.end.x].type === 'WHITE') {
        // 绘制新终点
        let xp = (this.form.end.x + 1) * 50
        let yp = (this.form.end.y + 1) * 50
        this.ctx.fillStyle = '#2ecc71'
        this.ctx.strokeStyle = 'black'
        this.ctx.fillRect(xp, yp, 50, 50)
        this.ctx.strokeRect(xp, yp, 50, 50);
        // 判断是否覆盖起点
        if (this.form.end.x === this.form.start.x && this.form.end.y === this.form.start.y) {
          this.isDrawStart = false;
        }
        this.isDrawEnd = true;
        this.prevEnd = {x: this.form.end.x, y: this.form.end.y}
      } else {
        this.$message.warning(`(${this.form.end.x},${this.form.end.y})不为路，无法设置为终点！`)
      }
    },
    /**
     * 处理csv文件上传成功
     * @param response
     */
    handleUploadOnSuccess(response) {
      this.points = response.data
      this.form.length = this.points.length
      this.form.width = this.points[0].length

      this.canvas = this.$refs.labyrinthArea;
      if (!this.canvas.getContext) {
        return
      }
      this.canvas.height = (this.form.length + 1) * 50
      this.canvas.width = (this.form.width + 1) * 50
      this.ctx = this.canvas.getContext('2d');

      this.drawLabyrinth(true)
      this.dialogVisible = false
    },
    /**
     * 下载迷宫 csv格式
     */
    downloadLabyrinth() {
      axios.get('http://localhost:81/api/generate/labyrinth/download/csv', {
        responseType: 'blob'
      }).then(response => {
        // 创建一个 Blob 对象
        const blob = new Blob([response.data], { type: 'text/csv' });
        // 创建一个隐藏的可下载链接
        const link = document.createElement('a');
        link.href = URL.createObjectURL(blob);
        link.setAttribute('download', 'labyrinth_' + new Date().getTime() + '.csv'); // 设置下载文件名
        document.body.appendChild(link);

        // 触发点击事件
        link.click();

        // 清理
        document.body.removeChild(link);
        URL.revokeObjectURL(link.href);
      })
    }
  }
}
</script>
<style scoped>
.labyrinth-area {
  width: 100%;
  height: calc(100vh - 20px - 150px);
  border: 2px solid #7f8c8d;
}

.appearance-area {
  width: 100%;
  height: calc(100vh - 20px - 150px);
  border: 2px solid #7f8c8d;
}

.distance {
  width: 100%;
  height: 50px;
}

.path {
  width: 100%;
  height: calc(100% - 50px);
  overflow-y: scroll;
}

.upload {
  display: flex;
  flex-direction: column;
  align-items: center;
}
</style>